﻿using System;
using System.Messaging;
using System.Threading.Tasks;
using log4net.Appender;
using log4net.Core;

namespace AppFx.BizTalk.Diagnostics.Log4net
{
    // ReSharper disable once InconsistentNaming
    public class MsmqAppender : AppenderSkeleton
    {        
        public string QueuePath { get; set; }
        public string ApplicationName { get; set; }
        public string EventType { get; set; }
        public bool Synchronous { get; set; }        
        public bool Enabled { get; set; }
        public string CorrelationIdPropertyName { get; set; }

        protected override void Append(LoggingEvent loggingEvent)
        {            
            var myLogEvent = new CustomLoggingEvent(loggingEvent)
            {
                ApplicationName = ApplicationName,
                EventType = EventType,
                CorrelationId = loggingEvent.LookupProperty(CorrelationIdPropertyName) as string
            };

            if (Enabled == false)
                return; //Chosen not to use logger

            if (Synchronous)
                AppendInternal(myLogEvent, 0);
            else
            {
                Task.Run(() => AppendInternal(myLogEvent, 0));
            }            
        }

        protected void AppendInternal(CustomLoggingEvent myLogEvent, int attemptNo)
        {
            try
            {                                                
                using (var queue = new MessageQueue(QueuePath))
                {    
                    var msg = new Message
                    {
                        Formatter = new ActiveXMessageFormatter(),
                        Label = string.Format("{0}: {1}", myLogEvent.ApplicationName, myLogEvent.RenderedMessage),
                        Body = myLogEvent.RenderedMessage, 
                        Recoverable = true
                    };
                    queue.Send(msg);                                                                 
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("The operation cannot be performed because the entity has been closed or aborted"))
                {
                    if (attemptNo < 3)
                    {
                        attemptNo++;
                        AppendInternal(myLogEvent, attemptNo);
                    }
                    else
                        ErrorHandler.Error("Error occured while publishing error", ex);
                }
                else                
                    ErrorHandler.Error("Error occured while publishing error", ex);                
            }
        }

        protected override void Append(LoggingEvent[] loggingEvents)
        {
            foreach(var loggingEvent in loggingEvents)
            {
                Append(loggingEvent);
            }
        }        
    }
}



